package cn.yueranzs.system.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.poi.excel.ExcelWriter;
import cn.yueranzs.config.AliyunOSSConfig;
import cn.yueranzs.handler.BusinessException;
import cn.yueranzs.response.ResultCode;
import cn.yueranzs.response.ResultPage;
import cn.yueranzs.response.UrlResultCode;
import cn.yueranzs.response.UserResultCode;
import cn.yueranzs.system.dto.user.AssignRoleChangeDto;
import cn.yueranzs.system.mapper.UserMapper;
import cn.yueranzs.system.pojo.Menu;
import cn.yueranzs.system.pojo.Role;
import cn.yueranzs.system.pojo.User;
import cn.yueranzs.system.pojo.UserRole;
import cn.yueranzs.system.service.UserRoleService;
import cn.yueranzs.system.service.UserService;
import cn.yueranzs.utils.AliyunOSSUtil;
import cn.yueranzs.utils.PaginationUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author yueranzs
 * @since 2021-11-04
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private AliyunOSSConfig aliyunOSSConfig;
    @Resource
    private UserRoleService userRoleService;


    @Transactional(propagation = Propagation.SUPPORTS,rollbackFor = Exception.class)
    @Override
    public ResultPage findUserList(User user, Page page) {
        if (ObjectUtil.isNull(page)) {
            //不计分页查全部
            page = PaginationUtil.getNewPage(1,-1);
        }
        Page<JSONObject> userPage = userMapper.findUserList(user, page);
        userPage.getRecords().forEach(users->{
            if (ObjectUtil.isNotEmpty(users.get("avatar"))) {
                users.set("avatarUrl",AliyunOSSUtil.getFileUrl(users.get("avatar").toString(),null));
                users.set("avatar",null);
            }
        });
        return new ResultPage(userPage.getTotal(),userPage.getRecords());
    }

    /**
     * 新增用户
     *
     * @param user
     */
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    @Override
    public void insertUser(User user) {
        user.setSalt(UserResultCode.USER_SALT.getMessage());
        user.setPassword(SecureUtil.md5(user.getPassword()));
        user.setStatus(UserResultCode.USER_STATUS.getCode());
        user.setCreateTime(DateUtil.date());
        user.setDeleted(ResultCode.NODELETE.getCode());
        User findUser = findUser(user);
        if (ObjectUtil.isNotNull(findUser)) {
            throw new BusinessException(UserResultCode.USER_ACCOUNT_ALREADY_EXIST.getCode(),UserResultCode.USER_ACCOUNT_ALREADY_EXIST.getMessage());
        }
        boolean save = save(user);
        if (!save) {
            throw new BusinessException(ResultCode.SAVEERROR.getCode(),ResultCode.SAVEERROR.getMessage());
        }else{
            if (ObjectUtil.isNotEmpty(user.getAvatar())) {
                //1.将处于临时文件夹的头像文件拷贝到新路径
                String imgPath = user.getAvatar().substring(user.getAvatar().lastIndexOf("/") + 1);
                String newPath = UrlResultCode.HEAD_PORTRAIT_URL.getMessage() + "/" + user.getId() + "/" + AliyunOSSUtil.getNowDate() + "/" + imgPath;
                AliyunOSSUtil.cpFile(user.getAvatar(), newPath);
                //2.删除临时头像文件
                AliyunOSSUtil.deleteFile(user.getAvatar());
                //3.修改用户头像路径
                user.setAvatar(aliyunOSSConfig.getFileDir() + newPath);
                user.setAvatarUrl(AliyunOSSUtil.getFileUrl(user.getAvatar(),null));
                updateById(user);
            }
        }
    }

    /**
     * 修改用户
     *
     * @param user
     * @return
     */
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    @Override
    public void updateUser(User user) {
        User oldUser = getById(user.getId());
        User findUser = findUser(user);
        if (ObjectUtil.isNotEmpty(user.getPassword())) {
            user.setPassword(SecureUtil.md5(user.getPassword()));
        }
        if (ObjectUtil.equals(user.getUsername(),oldUser.getUsername())) {
            user.setUsername(null);
        }
        //根据账号查出有此用户并且不是自己则抛出已有用户名存在
        if (ObjectUtil.isNotNull(findUser) && !ObjectUtil.equals(findUser.getId(),user.getId())) {
            throw new BusinessException(UserResultCode.USER_ACCOUNT_ALREADY_EXIST.getCode(),UserResultCode.USER_ACCOUNT_ALREADY_EXIST.getMessage());
        }
        updateById(user);
    }

    private User findUser(User user){
        User findUser = getOne(new QueryWrapper<User>().lambda()
                .select(User::getId, User::getUsername)
                .eq(User::getDeleted, ResultCode.NODELETE.getCode())
                .eq(User::getUsername, user.getUsername())
        );
        return findUser;
    }
    /**
     * 导出用户
     *
     * @param user
     */
    @Transactional(propagation = Propagation.SUPPORTS,rollbackFor = Exception.class)
    @Override
    public void excelUserList(HttpServletResponse response, User user) {
        //初始化时定义表名
        ExcelWriter writer = new ExcelWriter(true, "用户列表");
        //自定义标题别名
        Map<String, String> mapZhu = MapUtil.newHashMap(true);
        mapZhu.put("id", "编号");
        mapZhu.put("nickName", "昵称");
        mapZhu.put("userName", "用户名");
        mapZhu.put("sex", "性别");
        mapZhu.put("deptName", "所属部门");
        mapZhu.put("birth", "生日");
        mapZhu.put("email", "邮箱");
        mapZhu.put("phoneNumber", "电话");
        mapZhu.put("status", "是否有效");
        mapZhu.forEach(writer::addHeaderAlias);
        Page page = PaginationUtil.getNewPage(1, -1);
        Page<JSONObject> userPage = userMapper.findUserList(user, page);
        userPage.getRecords().forEach(jsonObject -> {
            jsonObject.set("departmentId",null);
            int status = Integer.parseInt(jsonObject.get("status").toString());
            int sex = Integer.parseInt(jsonObject.get("sex").toString());
            jsonObject.set("status",status==1 ? UserResultCode.USER_STATUS.getMessage() : UserResultCode.USER_NOT_STATUS.getMessage());
            jsonObject.set("sex",sex==0 ? "男" : (sex==1 ? "女" : "保密" ));
        } );
        writer.write(userPage.getRecords(), true);
        // 设置所有列宽
        writer.setColumnWidth(-1, 20);
        //写出xlsx
        ServletOutputStream out = null;
        try {
            //response为HttpServletResponse对象
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("用户列表", "UTF8") + ".xlsx");
            out = response.getOutputStream();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            writer.flush(out, true);
            writer.close();
            IoUtil.close(out);
        }

    }

    /**
     * 删除用户
     *
     * @param id
     */
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    @Override
    public void deleteUser(Long id) {
        User user = getById(id);
        if (ObjectUtil.isNotNull(user)) {
            //伪删除用户
            user.setModifiedTime(DateUtil.date());
            user.setDeleted(ResultCode.DELETE.getCode());
            updateById(user);
            //删除用户头像
            if (ObjectUtil.isNotEmpty(user.getAvatar())) {
                AliyunOSSUtil.deleteFile(user.getAvatar());
            }
        }
    }

    /**
     * 根据用户编号查询角色信息
     *
     * @param id
     * @return
     */
    @Transactional(propagation = Propagation.SUPPORTS,rollbackFor = Exception.class)
    @Override
    public List<Role> getRolesByUserId(Long id) {
        return userMapper.getRolesByUserId(id);
    }

    /**
     * 根据角色集合查询菜单信息
     *
     * @param roleIds
     * @return
     */
    @Transactional(propagation = Propagation.SUPPORTS,rollbackFor = Exception.class)
    @Override
    public List<Menu> getMenusByRoleIds(List<Long> roleIds) {
        return userMapper.getMenusByRoleIds(roleIds);
    }

    /**
     * 分配角色
     *
     * @param dto
     */
    @Override
    public void assignRole(AssignRoleChangeDto dto) {
        if (ObjectUtil.isNotEmpty(dto.getSaveRoleIds())) {
            //新增用户角色
            dto.getSaveRoleIds().forEach(roleId ->{
                UserRole userRole = new UserRole();
                userRole.setUserId(dto.getUserId());
                userRole.setRoleId(roleId);
                userRole.setCreateTime(DateUtil.date());
                userRole.setDelflag(ResultCode.NODELETE.getCode());
                userRoleService.save(userRole);
            });
        }
        if (ObjectUtil.isNotEmpty(dto.getDelRoleIds())) {
            //删除用户角色
            dto.getDelRoleIds().forEach(roleId ->{
                userRoleService.update(new UpdateWrapper<UserRole>().lambda()
                        .set(UserRole::getDelflag,ResultCode.DELETE.getCode())
                        .set(UserRole::getUpdateTime,DateUtil.date())
                        .eq(UserRole::getUserId,dto.getUserId())
                        .eq(UserRole::getRoleId,roleId)
                        .eq(UserRole::getDelflag,ResultCode.NODELETE.getCode())
                );
            });
        }
    }
}
